#
# Rakefile to build DocIndexer.
#

verbose true
nowrite false   # Set true when testing.

# Change the application version number and date here then run 'rake vers'
# command to update version number in source files.
VERS = '0.9.4.3'
VERS_DATE='2011-07-20'

# Tools.
HG = 'hg'

# Files and file locations
DOCS_DIR = './doc'
DIST_DIR = './dist'
BUILD_DIR = './build'
SETUP_DIR = './setup'

# Files.
DOC_HTML = File.join(DOCS_DIR, 'docindexer.html')
CHANGELOG_HTML = File.join(DOCS_DIR,'CHANGELOG.html')
WIZARD = File.join(SETUP_DIR, "docindexer-setup-#{VERS}.exe")
COM_SERVER = File.join(DIST_DIR, "docindexer_win32com.exe")
SOURCE_DIST = "docindexer-#{VERS}.zip"
WEB_FILES = FileList[WIZARD, DOC_HTML, CHANGELOG_HTML, SOURCE_DIST]

# File lists.
RESOURCES = FileList[%w{docsearch.ico docindex.ico}]
PYTHON_FILES = FileList['*.py', 'docindexer/*.py']
MANIFEST = FileList[(File.open('MANIFEST') {|f| f.read }).split]
WIN32_SOURCES = PYTHON_FILES + RESOURCES
DOC_DEPS = FileList[%w{./doc/docindexer.txt BUGS.txt ./doc/vba-example.txt}]

# Files with embedded version number.
VERSIONED_FILES = %w{
  VERSION
  docindexer-setup.iss
  docindexer_win32com.py
  docindex.py
  docsearch.py
  setup.py
  setup_win32.py
}

current_vers = (File.open('VERSION') {|f| f.read }).strip
if VERS != current_vers
  # Files updated by the version change ensure a rebuild.
  puts "updating version number from #{current_vers} to #{VERS}"
  VERSIONED_FILES.each do |fname|
    s = File.open(fname) {|f| f.read }
    if s.gsub!(/(?m)\b#{Regexp.escape(current_vers)}\b/, VERS)
      File.open(fname, 'w') {|f| f.write(s) }
    else
      fail "unable to update version in '#{fname}'"
    end
  end
  touch %w{./doc/docindexer.txt CHANGELOG.txt}
end

def win32?
  RUBY_PLATFORM =~ /win32/i
end

def requires_windows
  fail 'requires win32 platform' unless win32?
end

# Tools.
#
# win32 batch file can't be relied on to return a sensible exit status, use
# exe's instead.
#
PYTHON = win32? ? 'C:\python25\python.exe' : 'python'
PYCHECKER = win32? ? "#{PYTHON} C:/Python25/Lib/site-packages/pychecker/checker.py" : 'pychecker'
PYCHECKER_OPTS = ''
ASCIIDOC = win32? ? "#{PYTHON} C:/bin/asciidoc/asciidoc.py" : 'asciidoc'
XMLLINT = 'xmllint'
ASPELL = 'aspell'
CTAGS = 'ctags'
ISSC = "C:/Program Files/Inno Setup 5/iscc.exe"


#--------------------------------------------------------------------
# Tasks
#--------------------------------------------------------------------

task :default => :vers

desc 'make docs, zipball and installer wizard'
task :all => [:docs, :dist, :wizard]

desc 'print and, if necessary, update current version number'
task :vers do
  puts VERS
end

desc 'rebuild documentation'
task :docs => [DOC_HTML, CHANGELOG_HTML]

file DOC_HTML => DOC_DEPS do |t|
  dst = t.name
  src = t.prerequisites[0]
  if not win32? then
    # aspell(1) does not handle symlinks properly.
    sh %{"#{ASPELL}" check -p docindexer.dict "#{src}"}
  end
  opts = %{--unsafe -a toc -a toclevels=1 -a numbered -a "version=#{VERS}" -a "version-date=#{VERS_DATE}"}
  sh %{#{ASCIIDOC} #{opts} -o "#{dst}" "#{src}"}
  if not win32? then
    sh %{"#{XMLLINT}" --nonet --noout --valid --html "#{dst}"}
  end
end

file CHANGELOG_HTML => 'CHANGELOG.txt' do |t|
  dst = t.name
  src = t.prerequisites[0]
  opts = %{-a "version=#{VERS}" -a "version-date=#{VERS_DATE}"}
  sh %{#{ASCIIDOC} #{opts} -o "#{dst}" "#{src}"}
  if not win32? then
    sh %{"#{XMLLINT}" --nonet --noout --valid --html "#{dst}"}
  end
end

desc 'create ctags file'
task :tags do
  sh %{"#{CTAGS}" #{PYTHON_FILES.join(' ')}}
end

# A good idea would be to only check if the .pyc file was out of date, but it
# gets complicated because dependent modules are compiled but not checked so
# unless they are processed in dependency order they may miss getting checked.

desc 'pycheck all python files'
task :checkall do
  # exclude setup scripts, they make pychecker go mental.
  (PYTHON_FILES - FileList['setup*.py']).each { |f| sh %{#{PYCHECKER} #{PYCHECKER_OPTS} "#{f}"} }
end

desc 'pycheck python files in command-line args'
task :check do
  files = ARGV[1..-1]
  if files.size > 0
    files.each { |f| sh %{#{PYCHECKER} #{PYCHECKER_OPTS} "#{f}"} }
  else
    fail 'one or more files must be specified as command-line args'
  end
end

desc 'compile win32 setup wizard'
task :wizard => WIZARD
file WIZARD => :exes do
  requires_windows
  fail 'missing antiword executables' unless File.directory?('antiword')
  fail 'missing xpdf executables' unless File.directory?('xpdf')
  sh %{"#{ISSC}" docindexer-setup.iss}
end

desc 'build win32 executables'
task :exes => COM_SERVER
file COM_SERVER => WIN32_SOURCES do
  requires_windows
  rm_r Dir[File.join(DIST_DIR, '*')]
  sh %{#{PYTHON} setup_win32.py}
end

desc 'build source distribution'
task :dist do
  sh %{#{HG} man >MANIFEST}
  sh %{#{PYTHON} setup.py sdist --dist-dir . --formats=zip}
end

desc 'install docindexer package'
task :install do
  cmd = %{#{PYTHON} setup.py install}
  cmd = 'sudo ' + cmd unless win32?
  sh cmd
end

desc 'remove all generated files'
task :clobber do
  rm_f Dir[File.join(DIST_DIR,'*')]
  rm_f Dir[File.join(BUILD_DIR,'*')]
  rm_f Dir[File.join(DOCS_DIR,'*.html')]
  rm_f [SOURCE_DIST, WIZARD]
  rm_f PYTHON_FILES.ext('.pyc')
end

# The Rake upload task is separate because it's site specific.
if File.exists?('../upload.rake')
  load '../upload.rake'
end

# vim: set ft=ruby et ts=2 sw=2 sts=2:
